#include "tcp_receiver.hh"

// Dummy implementation of a TCP receiver

// For Lab 2, please replace with a real implementation that passes the
// automated checks run by `make check_lab2`.

template <typename... Targs>
void DUMMY_CODE(Targs &&.../* unused */) {}

using namespace std;

void TCPReceiver::segment_received(const TCPSegment &seg) {
    // Set the Initial Sequence Number if necessary.
    if (seg.header().syn) {
        _syn_received = true;
        _isn = seg.header().seqno;
    }
    if (!_syn_received) {
        return;
    }
    uint64_t idx = unwrap(seg.header().seqno, _isn, _reassembler.first_unassembled());
    bool eof = seg.header().fin;
    if (idx == 0 && !seg.payload().copy().empty() && !seg.header().syn) {
        return;
    }
    // printf("push idx_%ld\n", idx);
    _reassembler.push_substring(seg.payload().copy(), idx == 0 ? 0 : idx - 1, eof);

    if (_reassembler.eof()) {
        // printf("fin received!!!\n");
        _ackno = wrap(_reassembler.first_unassembled() + 2, _isn);  // count eof
    } else {
        _ackno = wrap(_reassembler.first_unassembled() + 1, _isn);
    }

    // printf("_reassembler.first_unacceptable(): %ld\n", _reassembler.first_unacceptable());
    // printf("_reassembler.first_unassembled(): %ld\n", _reassembler.first_unassembled());
}

// Returns an optional<WrappingInt32> containing the
// sequence number of the first byte that the receiver doesn’t already know.
//
// This is the windows’s left edge: the first byte the receiver is interested in receiving.
// If the ISN hasn’t been set yet, return an empty optional.
optional<WrappingInt32> TCPReceiver::ackno() const {
    if (!_syn_received) {
        return {};
    }
    return _ackno;
}

// Returns the distance between the “first unassembled” index
// (the index corresponding to the ackno) and the “first unacceptable” index.
size_t TCPReceiver::window_size() { return _reassembler.first_unacceptable() - _reassembler.first_unassembled(); }
